package com.app.service.impl.article;

import com.app.domain.bo.article.ArticleCommentBo;
import com.app.domain.page.Page;
import com.app.domain.po.article.ArticleCommentPo;
import com.app.domain.po.article.ArticlePo;
import com.app.domain.po.user.UserPo;
import com.app.domain.vo.article.ArticleCommentVo;
import com.app.domain.vo.article.ArticleVo;
import com.app.domain.vo.user.UserVo;
import com.app.framework.utils.*;
import com.app.mapper.article.ArticleCommentMapper;
import com.app.service.article.ArticleCommentService;
import com.app.service.article.ArticleCommonService;
import com.app.service.user.UserCommonService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import jakarta.annotation.Resource;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 文章评论方法实现
 */
@Service
public class ArticleCommentServiceImpl extends ServiceImpl<ArticleCommentMapper, ArticleCommentPo> implements ArticleCommentService {

    @Resource
    private UserCommonService userCommonService;

    @Resource
    private ArticleCommonService articleCommonService;

    /**
     * 获取全部评论
     *
     * @param bo 入参
     */
    @Override
    @Cacheable(cacheNames = "all_comment_list", key = "#bo.getPageNum")
    public Page<ArticleCommentVo> allComment(ArticleCommentBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        //查询评论
        List<ArticleCommentVo> articleCommentVos = baseMapper.selectAllComment(bo);
        if (CollectionUtils.isEmpty(articleCommentVos)) {
            return Page.restPage(new ArrayList<>());
        }
        //用户ID
        List<Long> userIds = new ArrayList<>();
        //文章ID
        List<Long> articleIds = new ArrayList<>();
        //插入用户ID/文章ID
        for (ArticleCommentVo articleCommentVo : articleCommentVos) {
            userIds.add(articleCommentVo.getUserId());
            articleIds.add(articleCommentVo.getArticleId());
        }
        //根据(用户ID/文章ID)批量查询用户和文章
        Map<Long, UserVo> userMap = userCommonService.getUserMap(userIds);
        Map<Long, ArticleVo> articleMap = articleCommonService.getArticleMap(articleIds);
        //写入用户信息和文章信息
        for (ArticleCommentVo articleCommentVo : articleCommentVos) {
            articleCommentVo.setUser(userMap.get(articleCommentVo.getUserId()));
            articleCommentVo.setArticle(articleMap.get(articleCommentVo.getArticleId()));
        }
        return Page.restPage(articleCommentVos);
    }

    /**
     * 用户评论列表
     *
     * @param bo 入参
     */
    @Override
    @Cacheable(cacheNames = "user_comment_list", key = "#bo.getUserId + ':' + #bo.getPageNum")
    public Page<ArticleCommentVo> userComment(ArticleCommentBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        //查询用户评论
        List<ArticleCommentVo> articleCommentVos = baseMapper.selectUserComment(bo.getUserId());
        return Page.restPage(articleCommentVos);
    }

    /**
     * 评论列表
     *
     * @param bo 入参
     */
    @Override
    @Cacheable(cacheNames = "article_comment_list", key = "#bo.getArticleId + ':' + #bo.getPageNum")
    public Page<ArticleCommentVo> lists(ArticleCommentBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        //查询所有父级评论
        List<ArticleCommentVo> allParentComment = baseMapper.selectParentComment(bo.getArticleId());
        //查询所有子级评论
        List<ArticleCommentVo> allSubComment = baseMapper.selectSubComment(bo.getArticleId());
        if (CollectionUtils.isEmpty(allParentComment)) {
            return Page.restPage(new ArrayList<>());
        }
        //用户ID
        List<Long> userIds = new ArrayList<>();
        //插入用户ID
        for (ArticleCommentVo parentComment : allParentComment) {
            Long userId = parentComment.getUserId();
            userIds.add(userId);
        }
        //插入用户ID
        for (ArticleCommentVo subComment : allSubComment) {
            userIds.add(subComment.getUserId());
            userIds.add(subComment.getReplyUserId());
        }
        //根据用户ID批量查询用户
        Map<Long, UserVo> userMap = userCommonService.getUserMap(userIds);
        for (ArticleCommentVo articleCommentVo : allParentComment) {
            articleCommentVo.setUser(userMap.get(articleCommentVo.getUserId()));
            List<ArticleCommentVo> subCommentList = new ArrayList<>();
            //计数器/记录已经添加的子评论数量
            int subCommentCount = 0;
            for (ArticleCommentVo subComment : allSubComment) {
                if (subComment.getMid().equals(articleCommentVo.getId()) && subCommentCount < 3) {
                    subComment.setUser(userMap.get(subComment.getUserId()));
                    subComment.setReplyUser(userMap.get(subComment.getReplyUserId()));
                    subCommentList.add(subComment);
                    subCommentCount++;
                }
            }
            articleCommentVo.setSubComment(subCommentList);
        }
        return Page.restPage(allParentComment);
    }

    /**
     * 查看更多
     *
     * @param bo 入参
     */
    @Override
    public Page<ArticleCommentVo> mores(ArticleCommentBo bo) {
        PageHelper.startPage(bo.getPageNum(), bo.getPageSize());
        //根据(文章ID/主评论ID)查询评论
        List<ArticleCommentVo> commentVos = baseMapper.selectSubCommentsByMid(bo.getArticleId(), bo.getMid());
        if (CollectionUtils.isEmpty(commentVos)) {
            return Page.restPage(new ArrayList<>());
        }
        //用户ID
        List<Long> userIds = new ArrayList<>();
        //插入用户ID
        for (ArticleCommentVo articleCommentVo : commentVos) {
            userIds.add(articleCommentVo.getUserId());
            userIds.add(articleCommentVo.getReplyUserId());
        }
        //根据用户ID批量查询用户信息
        Map<Long, UserVo> userMap = userCommonService.getUserMap(userIds);
        //写入用户信息
        for (ArticleCommentVo articleCommentVo : commentVos) {
            articleCommentVo.setUser(userMap.get(articleCommentVo.getUserId()));
            articleCommentVo.setReplyUser(userMap.get(articleCommentVo.getReplyUserId()));
        }
        return Page.restPage(commentVos);
    }

    /**
     * 添加评论
     *
     * @param bo 入参
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOne(ArticleCommentBo bo) {
        //登录用户ID
        Long loginUserId = TokenUtils.getLoginUserId();
        //主评论ID
        Long commentMid = bo.getMid();
        //文章ID
        Long articleId = bo.getArticleId();
        //回复对象ID
        Long replyUserId = bo.getReplyUserId();
        //查询文章实体
        ArticlePo articlePo = articleCommonService.getById(articleId);
        Assert.notNull(articlePo, "文章不存在");
        if (CollectionUtils.isNoNull(replyUserId)) {
            Assert.state(!replyUserId.equals(loginUserId), "自己不能回复自己");
            UserPo userPo = userCommonService.getById(replyUserId);
            Assert.notNull(userPo, "回复对象不存在");
        }
        //添加评论信息
        ArticleCommentPo articleCommentPo = CoBeanUtils.copy(bo, ArticleCommentPo.class);
        articleCommentPo.setIp(IpUtils.getIp());
        articleCommentPo.setUserId(loginUserId);
        articleCommentPo.setCreateTime(new Date());
        baseMapper.insert(articleCommentPo);
        if (CollectionUtils.isNoNull(commentMid)) {
            //更新子评论数量
            baseMapper.updateSubCommentCount(commentMid, 1);
        }
        //更新文章评论数量
        articleCommonService.updateCommentCount(articleId, 1);
        //删除缓存
        deleteRedisCache(articleId, loginUserId);
    }

    /**
     * 删除评论
     *
     * @param commentId 评论ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOne(Long commentId) {
        //查询评论
        ArticleCommentPo articleCommentPo = baseMapper.selectById(commentId);
        Assert.notNull(articleCommentPo, "评论不存在");
        //递归删除子评论并统计删掉的评论数
        int delCount = deleteSubComments(commentId);
        //更新对应的父评论的子评论数量
        if (CollectionUtils.isNoNull(articleCommentPo.getMid())) {
            //更新子评论数量
            baseMapper.updateSubCommentCount(articleCommentPo.getMid(), -delCount + 1);
        }
        //删除评论
        baseMapper.deleteById(commentId);
        //更新文章评论数量
        articleCommonService.updateCommentCount(articleCommentPo.getArticleId(), -delCount + 1);
        //刪除缓存
        deleteRedisCache(articleCommentPo.getArticleId(), articleCommentPo.getUserId());
    }

    /**
     * 屏蔽评论
     *
     * @param commentId 评论ID
     */
    @Override
    public void shield(Long commentId) {
        //查询评论
        ArticleCommentPo articleCommentPo = baseMapper.selectById(commentId);
        Assert.notNull(articleCommentPo, "评论不存在");
        articleCommentPo.setContent("该评论已被屏蔽");
        baseMapper.updateById(articleCommentPo);
        //删除缓存
        deleteRedisCache(articleCommentPo.getArticleId(), articleCommentPo.getUserId());
    }

    /**
     * 评论点赞
     *
     * @param commentId 评论ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void like(Long commentId) {
        ArticleCommentPo articleCommentPo = baseMapper.selectById(commentId);
        Assert.notNull(articleCommentPo, "评论不存在");
        Long articleId = articleCommentPo.getArticleId();
        //更新评论点赞数量
        baseMapper.updateCommentLikeCount(commentId);
        //刪除缓存
        RedisUtils.concatDeletes("article_comment_list::" + articleId + "*");
    }

    //--------------------------------------------------------------|↓|内部递归方法|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|内部递归方法|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|内部递归方法|↓|-----------------------------------------------------------------

    /**
     * 递归删除子级评论(返回删除评论的总数)
     *
     * @param pid 父级评论ID
     * @return 删除的评论总数
     */
    @Transactional(rollbackFor = Exception.class)
    public int deleteSubComments(Long pid) {
        int countDel = 0;
        List<ArticleCommentVo> articleCommentVos = baseMapper.selectSubCommentsByPid(pid);
        if (CollectionUtils.isEmpty(articleCommentVos)) {
            List<Long> commentIds = new ArrayList<>();
            for (ArticleCommentVo articleCommentVo : articleCommentVos) {
                commentIds.add(articleCommentVo.getId());
                countDel++;
                countDel += deleteSubComments(articleCommentVo.getId());
            }
            removeBatchByIds(commentIds);
        }
        return countDel;
    }

    //--------------------------------------------------------------|↓|Redis缓存删除|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|Redis缓存删除|↓|-----------------------------------------------------------------
    //--------------------------------------------------------------|↓|Redis缓存删除|↓|-----------------------------------------------------------------

    /**
     * 删除缓存
     *
     * @param articleId 文章ID
     * @param userId    用户ID
     */
    private void deleteRedisCache(Long articleId, Long userId) {
        if (CollectionUtils.isNoNull(userId)) {
            RedisUtils.deleteJsonHash("user_counts", userId);
            RedisUtils.concatDeletes("user_comment_list::" + userId + "*");
        }
        if (CollectionUtils.isNoNull(articleId)) {
            RedisUtils.concatDeletes("article_comment_list::" + articleId + "*");
        }
        RedisUtils.concatDeletes("all_comment_list::*");
    }

}